
#include "stdafx.h"

#include "pf_solid.h"

#include "pf_graphicview.h"
#include "pf_painter.h"


/**
 * Default constructor.
 */
PF_Solid::PF_Solid(PF_Container* parent,
                   const PF_SolidAttribute& d)
        :PF_AtomicEntity(parent), data(d) {
    calculateBorders();
}



/**
 * @return Corner number 'num'. 
 */
PF_Vector PF_Solid::getCorner(int num) {
    if (num>=0 && num<4) {
        return data.corner[num];
    } else {
        PF_DEBUG->print("Illegal corner requested from Solid",
                        PF_Debug::D_WARNING);
        return PF_Vector(false);
    }
}



/**
 * Shapes this Solid into a standard arrow (used in dimensions).
 *
 * @param point The point the arrow points to.
 * @param angle Direction of the arrow.
 * @param arrowSize Size of arrow (length).
 */
void PF_Solid::shapeArrow(const PF_Vector& point,
                          double angle,
                          double arrowSize) {

    double cosv1, sinv1, cosv2, sinv2;
    double arrowSide = arrowSize/cos(0.165);

    cosv1 = cos(angle+0.165)*arrowSide;
    sinv1 = sin(angle+0.165)*arrowSide;
    cosv2 = cos(angle-0.165)*arrowSide;
    sinv2 = sin(angle-0.165)*arrowSide;

    data.corner[0] = point;
    data.corner[1] = PF_Vector(point.x - cosv1, point.y - sinv1);
    data.corner[2] = PF_Vector(point.x - cosv2, point.y - sinv2);
    data.corner[3] = PF_Vector(false);

    calculateBorders();
}



void PF_Solid::calculateBorders() {
    resetBorders();

    for (int i=0; i<4; ++i) {
        if (data.corner[i].valid) {
            minV = PF_Vector::minimum(minV, data.corner[i]);
            maxV = PF_Vector::maximum(maxV, data.corner[i]);
        }
    }
}



PF_Vector PF_Solid::getNearestEndpoint(const PF_Vector& coord, double* dist) {

    double minDist = LX_DOUBLEMAX;
    double curDist;
    PF_Vector ret;

    for (int i=0; i<4; ++i) {
        if (data.corner[i].valid) {
            curDist = data.corner[i].distanceTo(coord);
            if (curDist<minDist) {
                ret = data.corner[i];
                minDist = curDist;
            }
        }
    }

    if (dist!=NULL) {
        *dist = minDist;
    }

    return ret;
}



/**
 * @todo Implement this.
 */
PF_Vector PF_Solid::getNearestPointOnEntity(const PF_Vector& /*coord*/,
        bool /*onEntity*/, double* /*dist*/, PF_Entity** /*entity*/) {

    PF_Vector ret(false);
    return ret;
}



PF_Vector PF_Solid::getNearestCenter(const PF_Vector& /*coord*/,
                                     double* dist) {

    if (dist!=NULL) {
        *dist = LX_DOUBLEMAX;
    }

    return PF_Vector(false);
}



PF_Vector PF_Solid::getNearestMiddle(const PF_Vector& /*coord*/,
                                     double* dist) {
    if (dist!=NULL) {
        *dist = LX_DOUBLEMAX;
    }
    return PF_Vector(false);
}



PF_Vector PF_Solid::getNearestDist(double /*distance*/,
                                   const PF_Vector& /*coord*/,
                                   double* dist) {
    if (dist!=NULL) {
        *dist = LX_DOUBLEMAX;
    }
    return PF_Vector(false);
}



/**
 * @return Distance from one of the boundry lines of this solid to given point.
 *
 * @todo implement
 */
double PF_Solid::getDistanceToPoint(const PF_Vector& /*coord*/,
                                    PF_Entity** /*entity*/,
                                    LX_Define::ResolveLevel /*level*/,
								    double /*solidDist*/) {
    return LX_DOUBLEMAX;
}



void PF_Solid::move(PF_Vector offset) {
    for (int i=0; i<4; ++i) {
        data.corner[i].move(offset);
    }
    calculateBorders();
}



void PF_Solid::rotate(PF_Vector center, double angle) {
    for (int i=0; i<4; ++i) {
        data.corner[i].rotate(center, angle);
    }
    calculateBorders();
}



void PF_Solid::scale(PF_Vector center, PF_Vector factor) {
    for (int i=0; i<4; ++i) {
        data.corner[i].scale(center, factor);
    }
    calculateBorders();
}



void PF_Solid::mirror(PF_Vector axisPoint1, PF_Vector axisPoint2) {
    for (int i=0; i<4; ++i) {
        data.corner[i].mirror(axisPoint1, axisPoint2);
    }
    calculateBorders();
}


void PF_Solid::draw(PF_Painter* painter, PF_GraphicView* view, 
	double /*patternOffset*/) {

    if (painter==NULL || view==NULL) {
        return;
    }

    PF_SolidAttribute d = getData();
    if (isTriangle()) {
        painter->fillTriangle(view->toGui(getCorner(0)),
                              view->toGui(getCorner(1)),
                              view->toGui(getCorner(2)));
    }

}


/**
 * Dumps the point's data to stdout.
 */
std::ostream& operator << (std::ostream& os, const PF_Solid& p) {
    os << " Solid: " << p.getData() << "\n";
    return os;
}

